// Tools区域
(function() {
    var Tools = {
        // 获取一个范围内的随机数
        getRandom: function(min, max) {
            min = Math.ceil(min);
            max = Math.floor(max);
            return Math.floor(Math.random() * (max - min + 1)) + min;
        },
        // 获取随机颜色
        getColor: function() {
            //rgb()里面存储三个值,保证他们在0-255范围内的随机,就获得随机颜色;
            const r = this.getRandom(0, 255);
            const g = this.getRandom(0, 255);
            const b = this.getRandom(0, 255);
            return `rgb(${r},${g},${b})`;
        }
    };
    window.Tools = Tools;
})();

//封装有关Food对象的函数
(function(window) {
    // 定义一个全局变量
    let site = "absolute";
    //封装Food的构造函数
    function Food(option) {
        // 确保传进来的数据是对象
        option = option instanceof Object ? option : {};
        Object.assign(this, option);
        //定义一个数组,存储push进去的对象属性
        this.element = [];
    };
    //Food渲染页面到页面的方法
    Food.prototype.render = function(map) {
        //创建一个新的元素
        const ele = document.createElement('div');
        //确定Food的left、top位置
        this.x = Tools.getRandom(0, map.clientWidth / this.width - 1) * this.width;
        this.y = Tools.getRandom(0, map.clientHeight / this.height - 1) * this.height;
        //添加对应的样式
        ele.style.position = site;
        ele.style.left = this.x + 'px';
        ele.style.top = this.y + 'px';
        ele.style.height = this.height + 'px';
        ele.style.width = this.width + 'px';
        ele.style.backgroundColor = this.backgroundColor;
        ele.style.borderRadius = `50%`;
        // 让新元素添加到map中
        map.appendChild(ele);
        // 将新元素添加的数组,利用后期调用和删除
        this.element.push(ele);
    };
    //Food移除页面
    Food.prototype.remove = function(map, i) {
        //在map上移除该元素
        map.removeChild(this.element[i]);
        //将元素 从数组中删除
        this.element.splice(i, 1);
    };
    window.Food = Food;
})(window);

//封装有关Snake对象的函数
(function() {
    // 定义一个定位的变量
    let site = "absolute";
    // 封装有关Snake的函数
    function Snake(option) {
        option = option instanceof Object ? option : {}
        Object.assign(this, option);
        //确定蛇身的方块位置
        this.body = [
            { x: 3, y: 2, color: Tools.getColor() },
            { x: 2, y: 2, color: 'skyblue' },
            { x: 1, y: 2, color: 'skyblue' },
        ];
        // 确定蛇的初始位置
        this.direction = 'right';
        // 定义空数组接受创建的组成蛇的方块元素
        this.element = [];

    };
    //Snake渲染页面的函数
    Snake.prototype.render = function(map) {
        for (let i = 0, len = this.body.length; i < len; i++) {
            //创建组成蛇的元素
            const ele = document.createElement('div');
            // 根据数组的每一项数据生成新的元素
            const per = this.body[i];
            //蛇的对应样式
            ele.style.width = this.width + 'px';
            ele.style.height = this.height + 'px';
            ele.style.backgroundColor = per.color;
            ele.style.position = site;
            ele.style.left = per.x * this.width + 'px';
            ele.style.top = per.y * this.height + 'px';
            // 渲染到指定的父级元素中
            map.appendChild(ele);
            // 将新的元素添加到数组中
            this.element.push(ele);
        }
    };
    // Snake 的运动
    Snake.prototype.move = function() {
        // 蛇身每一节都要变成上一节
        for (var i = this.body.length - 1; i > 0; i--) {
            this.body[i].x = this.body[i - 1].x;
            this.body[i].y = this.body[i - 1].y
        }
        // 存储头部的位置
        var head = this.body[0];
        switch (this.direction) {
            case "right":
                head.x += 1;
                break;
            case "left":
                head.x -= 1;
                break;
            case "top":
                head.y -= 1;
                break;

            case "bottom":
                head.y += 1;
                break;
        };

    };
    //因为调用move函数后,需要通过render函数来进行渲染,
    // 相当于又往数组中添加了新的元素,造成了多余元素.所以得清除上一次生成的元素
    Snake.prototype.remove = function(map) {
        for (let i = this.element.length - 1; i >= 0; i--) {
            map.removeChild(this.element[i]);
        }
        this.element = [];
    };
    window.Snake = Snake;
})();

//封装有关Game对象的函数
(function() {
    // 定义一个分数的变量
    let score = 0;

    function Game(map) {
        //创建food实例对象
        this.food = new Food({
            width: 20,
            height: 20,
            backgroundColor: Tools.getColor(),
            x: 0,
            y: 0,
        });
        //创建snake实例对象
        this.snake = new Snake({
            width: 20,
            height: 20,
        });
        // 地图实物
        this.map = map;
        //吃到食物的得分
        // this.score = 0;
        _this = this;
    }

    // 游戏开始时的状态
    Game.prototype.start = function() {
        //food被渲染在页面上
        this.food.render(map);
        this.food.render(map);
        //snake被渲染在页面上
        this.snake.render(map);
        //snake自己移动起来
        snakeMove();
        //snake改变移动方向
        keyMove();
    };
    //蛇的通过按键转换方向函数
    function keyMove() {
        document.onkeydown = function(e) {
            // 获取按键的ascllc值
            // console.log(e.keyCode);
            // 根据按键的ascllc值,来改变direction的值
            switch (e.keyCode) {
                case 37:
                    _this.snake.direction = 'left';
                    break;
                case 38:
                    _this.snake.direction = 'top';
                    break;
                case 39:
                    _this.snake.direction = 'right';
                    break;
                case 40:
                    _this.snake.direction = 'bottom';
                    break;
            }
        }
    };
    //蛇移动函数
    function snakeMove() {

        //定义一个定时器
        let timer = setInterval(function() {
            //snake运动起来
            _this.snake.move();
            //先删除自己的原来元素
            _this.snake.remove(_this.map);
            //在重新渲染新元素
            _this.snake.render(_this.map);
            //获取到蛇头位置
            const sHX = _this.snake.body[0].x;
            const sHY = _this.snake.body[0].y;
            const sHeadX = sHX * _this.snake.width;
            const sHeadY = sHY * _this.snake.height;
            // console.log(sHeadX, sHeadY);
            //记录屏幕最大位置的份数
            const maxX = _this.map.clientWidth / _this.snake.width;
            const maxY = _this.map.clientHeight / _this.snake.height;
            // console.log(maxX, maxY);
            //    蛇与食物之间的关系
            for (let i = 0; i < _this.food.element.length; i++) {
                //判断蛇是否吃到食物
                if (sHeadX == _this.food.element[i].offsetLeft && sHeadY == _this.food.element[i].offsetTop) {
                    //吃到食物,食物消失,并重新渲染
                    _this.food.remove(_this.map, i);
                    _this.food.render(_this.map);
                    //蛇的长度要增加(得到原来蛇身snake.body最后一位的下标,是因为新的蛇节将占有上一个蛇节的位置)
                    const snakeLe = _this.snake.body[_this.snake.body.length - 1];
                    _this.snake.body.push({
                        x: snakeLe.x,
                        y: snakeLe.y,
                        color: snakeLe.color
                    });
                    //吃到食物后的分数
                    grade()

                }
            }
            //判断蛇头是否触碰到屏幕
            if (sHX < 0 || sHX >= maxX || sHY < 0 || sHY >= maxY) {
                clearInterval(timer);
                if (confirm(`游戏结束,你的总成绩为${score}。是否重新开始？`)) {
                    location.reload();
                }

            }
        }, 150)
    };
    //获取score的函数
    function grade() {
        score += 1;
        // console.log(score);
        const div = document.getElementById('score');
        div.innerHTML = `<div>总分为:${score}</div>`
    };
    window.Game = Game;
})();

(function() {
    const map = document.getElementById('map');
    const game = new Game(map);
    game.start()
})();